#include "vcd-usb-network.h"
#include <gtk/gtk.h>
#include <gio/gio.h>
#include "../vcd-common-api/vcd-log.h"

extern gboolean vcd_usb_redir(GtkWidget* btn, gpointer pt);

static void parse_msg(VcdUsbCtx* vcd_usb_ctx,char*data,int len){

    #define MAX_BUF_SIZE 1000
    static int index;
    static char* buf;
    if(!buf)
        buf = calloc(1,MAX_BUF_SIZE);

    if(index+len > MAX_BUF_SIZE)
        return;

    memcpy(buf+index,data,len);
    index += len;

    while(index >= sizeof(VcdMsgHeader)){
        VcdMsgHeader* header = (VcdMsgHeader*)buf;
        if(index >= header->length){
            char* tmp = calloc(1,header->length);
            memcpy(tmp,buf,header->length);

            if(vcd_usb_ctx->msg_callback)
                vcd_usb_ctx->msg_callback((VcdMsgHeader*)tmp,vcd_usb_ctx);

            M_DEBUG("parse_msg type:%d len:%d ",header->type,header->length);

            if(index - header->length > 0)
                memmove(buf,buf+header->length,MAX_BUF_SIZE - header->length);
            index -= header->length;
        }else{
            break;
        }
    }
}

gboolean read_msg(GIOChannel *channel, GIOCondition condition, gpointer data)
{
   VcdUsbCtx* vcd_usb_ctx = data;
   gsize len = 0;
   char buf[500] = {0};
   int size = 500;
   GError* error = NULL;

   GIOStatus ret = g_io_channel_read_chars(channel,buf,size,&len,&error);
   //GIOStatus ret = g_io_channel_read(channel,buf,size,&len);
   if (ret == G_IO_STATUS_ERROR || ret == G_IO_STATUS_EOF){
       //g_error ("Error reading: %s\n", error ? error->message : " ");
       gtk_main_quit();
       return FALSE;
   }
   else {
       if(len > 0){
           if(vcd_usb_ctx->is_use_spice_topbar){
                parse_msg(vcd_usb_ctx,buf,len);
           }else{
                M_DEBUG("parent => vcd-usb: show usb redir window");
                vcd_usb_redir(NULL,vcd_usb_ctx->usb_rdir);
           }
       }
       return TRUE;
   }
}

void vcd_usb_network_send(VcdUsbCtx* vcd_usb_ctx, char* data,int len){

    if(!vcd_usb_ctx || !vcd_usb_ctx->io_channel || !data || !len) return;

    GIOChannel* channel = vcd_usb_ctx->io_channel;
    char* pdata = data;
    int n = 0;

    while(n < len){
        g_io_channel_write(channel,pdata+n,len-n,&n);
    }

}

gboolean vcd_usb_network_start(VcdUsbCtx* vcd_usb_ctx){

    int parent_port = vcd_usb_ctx->parent_port;

    M_DEBUG("vcd_usb_network_start parent_port:%d",parent_port);
    if(parent_port <= 0 ) return FALSE;

    gboolean bError = FALSE;
    GError*  err = NULL;
    GSocket *socket = g_socket_new(G_SOCKET_FAMILY_IPV4, G_SOCKET_TYPE_STREAM,G_SOCKET_PROTOCOL_TCP,&err);
    GSocketAddress *addr = g_inet_socket_address_new_from_string("127.0.0.1",parent_port);
    if(!addr)
        goto failed;

    err = NULL;
    //g_socket_set_blocking(socket,0);
    //g_socket_set_timeout(socket,5);
    bError = g_socket_connect(socket,addr,NULL,&err);
    M_DEBUG("g_socket_connect bError:%d err:%s",bError,err ? err->message : " null");

    err = NULL;
    g_socket_condition_timed_wait(socket,G_IO_IN | G_IO_OUT | G_IO_NVAL | G_IO_ERR | G_IO_HUP, 1000*1000*2,NULL,&err);
    if(err)
        goto failed;

    err = NULL;
    bError = g_socket_check_connect_result(socket,&err);
    M_DEBUG("g_socket_check_connect_result bError:%d err:%s",bError,err ? err->message : " null");
    if(err)
        goto failed;


    gint fd = g_socket_get_fd(socket);
    GIOChannel *channel = g_io_channel_unix_new(fd);
    if (!channel) {
        M_DEBUG("g_io_channel_unix_new failed");
        goto failed;
    }
    g_io_channel_set_encoding(channel,NULL,NULL);
    g_io_add_watch(channel, G_IO_IN | G_IO_ERR | G_IO_HUP, (GIOFunc)read_msg, vcd_usb_ctx);
    g_io_channel_unref(channel);

    vcd_usb_ctx->io_channel = channel;
    return TRUE;

failed:
    M_DEBUG("vcd_usb_network_start failed");
    return FALSE;
}











